// Application/Services/UserService.cs
using System.Data;
using Microsoft.EntityFrameworkCore;
using UniversalAdmin.Application.Common;
using UniversalAdmin.Application.DTOs;
using UniversalAdmin.Application.Features.Users.Queries;
using UniversalAdmin.Domain.Entities;
using UniversalAdmin.Domain.Interfaces;
using UniversalAdmin.Domain.Repositories;
using UniversalAdmin.Infrastructure.Data;

namespace UniversalAdmin.Application.Services;

public class UserService : IUserService
{
  private readonly IUnitOfWork _uow;
  private readonly IMenuRepository _menuRepo;
  private readonly UniversalAdminDbContext _dbContext;

  public UserService(IUnitOfWork uow, IMenuRepository menuRepo, UniversalAdminDbContext dbContext)
  {
    _uow = uow;
    _menuRepo = menuRepo;
    _dbContext = dbContext;
  }

  public async Task<PagedResult<UserDto>> GetUsersAsync(UserQueryParameters param)
  {
    var (items, totalCount) = await _uow.UserRepository.GetPagedUsersAsync(
        keyword: param.Keyword,
        isActive: param.IsActive,
        pageIndex: param.PageIndex,
        pageSize: param.PageSize);

    var dtos = items.Select(ToDto).ToList();

    return new PagedResult<UserDto>
    {
      Items = dtos,
      TotalCount = totalCount,
      PageIndex = param.PageIndex,
      PageSize = param.PageSize
    };
  }

  public async Task<UserDto> GetUserByIdAsync(int id)
  {
    var user = await _uow.UserRepository.GetUserWithRolesAsync(id)
               ?? throw new KeyNotFoundException("用户不存在");
    return ToDto(user);
  }

  public async Task<UserDto> CreateUserAsync(CreateUserDto dto)
  {
    // 1. 唯一校验
    if (await _uow.UserRepository.IsUsernameExistsAsync(dto.Username))
      throw new ArgumentException("用户名已存在");
    if (await _uow.UserRepository.IsEmailExistsAsync(dto.Email))
      throw new ArgumentException("邮箱已存在");

    // 2. 创建实体
    var user = new User
    {
      Username = dto.Username,
      Email = dto.Email,
      Phone = dto.Phone,
      Avatar = dto.Avatar,
      IsActive = dto.IsActive,
      CreatedAt = DateTime.UtcNow,
      UpdatedAt = DateTime.UtcNow,
      Password = BCrypt.Net.BCrypt.HashPassword(dto.Password)
    };
    await _uow.UserRepository.AddAsync(user);
    await _uow.SaveChangesAsync();

    // 3. 关联角色
    foreach (var rid in dto.RoleIds)
    {
      await _uow.ExecuteSqlRawAsync(
          "INSERT INTO user_roles (user_id, role_id) VALUES ({0}, {1})",
          user.Id, rid);
    }

    return await GetUserByIdAsync(user.Id);
  }

  public async Task<UserWithMenusDto> GetUserWithMenusAsync(int userId)
  {
    var user = await _uow.UserRepository.GetUserWithRolesAsync(userId)
                 ?? throw new KeyNotFoundException("用户不存在");

    var roleIds = user.UserRoles?.Select(ur => ur.RoleId).ToList() ?? new List<int>();
    var roles = (await _uow.RoleRepository.GetByIdsAsync(roleIds))
            .Where(r => r != null)
            .Cast<Role>()
            .ToList();

    var menus = new List<MenuDto>();
    foreach (var rid in roleIds)
    {
      var roleMenus = await _menuRepo.GetMenusByRoleIdAsync(rid);
      menus.AddRange(roleMenus.Select(m => new MenuDto
      {
        Id = m.Id,
        Name = m.Name,
        Path = m.Path,
        Icon = m.Icon,
        ParentId = m.ParentId,
        Sort = m.Sort,
        IsActive = m.IsActive,
        Children = new()
      }));
    }

    return new UserWithMenusDto
    {
      Id = user.Id,
      Username = user.Username,
      Email = user.Email,
      Phone = user.Phone,
      Avatar = user.Avatar,
      IsActive = user.IsActive,
      CreatedAt = user.CreatedAt,
      UpdatedAt = user.UpdatedAt,
      Roles = roles.Select(r => new RoleDto
      {
        Id = r.Id,
        Name = r.Name
      }).ToList(),
      Menus = menus.DistinctBy(m => m.Id).ToList()
    };
  }

  public async Task<PagedResult<UserDto>> SearchUsersAsync(string? userName, string? email, int page, int size)
  {
    var query = _dbContext.Users
        .Include(u => u.UserRoles)
        .ThenInclude(ur => ur.Role)
        .Where(u => u.IsActive);

    if (!string.IsNullOrWhiteSpace(userName))
      query = query.Where(u => u.Username.Contains(userName));

    if (!string.IsNullOrWhiteSpace(email))
      query = query.Where(u => u.Email != null && u.Email.Contains(email));

    var totalCount = await query.CountAsync();
    
    var users = await query
        .OrderBy(u => u.Username)
        .Skip((page - 1) * size)
        .Take(size)
        .ToListAsync();

    var items = users.Select(ToDto).ToList();

    return new PagedResult<UserDto>
    {
      Items = items,
      TotalCount = totalCount,
      PageIndex = page,
      PageSize = size
    };
  }

  public async Task<UserDto> UpdateUserAsync(int id, UpdateUserDto dto)
  {
    var user = await _uow.UserRepository.GetUserWithRolesAsync(id)
               ?? throw new KeyNotFoundException("用户不存在");

    // 唯一性校验（排除自身）
    if (await _uow.UserRepository.IsUsernameExistsAsync(dto.Username, id))
      throw new ArgumentException("用户名已存在");
    if (await _uow.UserRepository.IsEmailExistsAsync(dto.Email, id))
      throw new ArgumentException("邮箱已存在");

    user.Username = dto.Username;
    user.Email = dto.Email;
    user.Phone = dto.Phone;
    user.Avatar = dto.Avatar;
    user.IsActive = dto.IsActive;
    user.UpdatedAt = DateTime.UtcNow;

    await _uow.UserRepository.UpdateAsync(user);
    await _uow.SaveChangesAsync();

    // 先删后插角色
    await _uow.ExecuteSqlRawAsync("DELETE FROM user_roles WHERE user_id = {0}", id);
    foreach (var rid in dto.RoleIds)
    {
      await _uow.ExecuteSqlRawAsync(
          "INSERT INTO user_roles (user_id, role_id) VALUES ({0}, {1})",
          id, rid);
    }

    return await GetUserByIdAsync(id);
  }

  public async Task AssignRolesAsync(int userId, List<int> roleIds)
  {
    var user = await _uow.UserRepository.GetByIdAsync(userId)
               ?? throw new KeyNotFoundException("用户不存在");

    // 1. 清空旧角色
    await _uow.ExecuteSqlRawAsync("DELETE FROM user_roles WHERE user_id = {0}", userId);

    // 2. 写入新角色
    foreach (var rid in roleIds.Distinct())
    {
      await _uow.ExecuteSqlRawAsync(
          "INSERT INTO user_roles (user_id, role_id) VALUES ({0}, {1})", userId, rid);
    }
  }

  public async Task DeleteUserAsync(int id)
  {
    var user = await _uow.UserRepository.GetByIdAsync(id);
    if (user == null) throw new KeyNotFoundException("用户不存在");

    await _uow.UserRepository.RemoveAsync(user);
    await _uow.SaveChangesAsync();
  }

  public async Task<bool> ChangePasswordAsync(int userId, ChangePasswordDto dto)
  {
    var user = await _uow.UserRepository.GetByIdAsync(userId);
    if (user == null) return false;

    user.Password = BCrypt.Net.BCrypt.HashPassword(dto.NewPassword);
    user.UpdatedAt = DateTime.UtcNow;

    await _uow.UserRepository.UpdateAsync(user);
    await _uow.SaveChangesAsync();
    return true;
  }

  /* ---------- 内部转换 ---------- */
  private static UserDto ToDto(User user)
  {
    return new UserDto
    {
      Id = user.Id,
      Username = user.Username,
      Email = user.Email,
      Phone = user.Phone,
      Avatar = user.Avatar,
      IsActive = user.IsActive,
      CreatedAt = user.CreatedAt,
      UpdatedAt = user.UpdatedAt,
      Roles = user.UserRoles?.Select(ur => new RoleDto
      {
        Id = ur.Role!.Id,
        Name = ur.Role.Name,
        Description = ur.Role.Description,
        IsActive = ur.Role.IsActive,
        CreatedAt = ur.Role.CreatedAt,
        UpdatedAt = ur.Role.UpdatedAt,
        UserCount = 0, // 如有需要可再查
        Menus = new()  // 按需填充
      }).ToList() ?? new List<RoleDto>()
    };
  }

}

